#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
优化版日志集成模块

本模块整合了系统日志和操作日志功能，提供统一、规范的日志记录接口，
支持带上下文的日志记录、异常处理、性能监控等高级功能。
"""

import os
import sys
import json
import time
import socket
import logging
import logging.handlers
import traceback
from datetime import datetime
from typing import Optional, Dict, Any, Callable, Union

# 确保中文显示正常
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8')

# 日志级别常量，便于统一使用
LOG_LEVELS = {
    'DEBUG': 'DEBUG',
    'INFO': 'INFO',
    'WARNING': 'WARNING',
    'ERROR': 'ERROR',
    'CRITICAL': 'CRITICAL'
}

# 日志模块初始化状态
_logger_initialized = False
_system_logger = None
_operation_logger = None


# =============================================================================
# 系统日志相关功能
# =============================================================================

def _get_logging_config():
    """
    从配置文件获取日志设置
    
    Returns:
        dict: 日志配置字典
    """
    try:
        from config_utils import ConfigManager
        return ConfigManager.get_logging_config()
    except Exception as e:
        # 出错时使用默认配置
        return {
            'log_dir': 'logs',
            'log_level': 'INFO',
            'max_log_size': 10 * 1024 * 1024,
            'backup_count': 5,
            'enable_console': True
        }


def _ensure_log_directory(log_dir):
    """
    确保日志目录存在
    
    Args:
        log_dir: 日志目录路径
    """
    try:
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
    except Exception as e:
        # 如果创建目录失败，使用当前目录
        print(f"警告: 无法创建日志目录 {log_dir}, 使用当前目录: {str(e)}")
        return os.getcwd()
    return log_dir


class EnhancedFormatter(logging.Formatter):
    """
    增强的日志格式化器，支持自定义格式和消息截断
    """
    def __init__(self, fmt=None, datefmt=None, max_length=1000):
        """
        初始化日志格式化器
        
        Args:
            fmt: 日志格式
            datefmt: 日期格式
            max_length: 最大消息长度，超过将被截断
        """
        if fmt is None:
            fmt = '%(asctime)s [%(levelname)s] [%(module)s:%(funcName)s:%(lineno)d] %(message)s'
        super().__init__(fmt, datefmt)
        self.max_length = max_length
    
    def format(self, record):
        """
        格式化日志记录
        
        Args:
            record: 日志记录对象
            
        Returns:
            str: 格式化后的日志字符串
        """
        # 截断过长的消息
        if len(record.msg) > self.max_length:
            record.msg = record.msg[:self.max_length] + "... [消息过长已截断]"
        return super().format(record)


def _initialize_system_logger():
    """
    初始化系统日志记录器
    
    Returns:
        logging.Logger: 初始化后的日志记录器
    """
    global _logger_initialized, _system_logger
    
    if _logger_initialized and _system_logger:
        return _system_logger
    
    # 获取配置
    config = _get_logging_config()
    log_dir = _ensure_log_directory(config['log_dir'])
    
    # 创建logger
    logger = logging.getLogger('rent_system')
    logger.setLevel(getattr(logging, config['log_level'], logging.INFO))
    
    # 清除现有处理器
    if logger.handlers:
        for handler in logger.handlers:
            logger.removeHandler(handler)
    
    # 文件处理器
    log_filename = os.path.join(log_dir, f"system_{datetime.now().strftime('%Y%m%d')}.log")
    file_handler = logging.handlers.RotatingFileHandler(
        log_filename,
        maxBytes=config['max_log_size'],
        backupCount=config['backup_count'],
        encoding='utf-8'
    )
    file_handler.setFormatter(EnhancedFormatter())
    logger.addHandler(file_handler)
    
    # 控制台处理器
    if config['enable_console']:
        console_handler = logging.StreamHandler()
        console_handler.setFormatter(EnhancedFormatter())
        logger.addHandler(console_handler)
    
    _logger_initialized = True
    _system_logger = logger
    return logger


def _get_system_logger():
    """
    获取系统日志记录器
    
    Returns:
        logging.Logger: 系统日志记录器
    """
    global _system_logger
    if not _system_logger:
        _initialize_system_logger()
    return _system_logger


# =============================================================================
# 系统日志记录函数
# =============================================================================

def log_debug(message: str, context: Optional[Dict] = None) -> None:
    """
    记录调试级别日志
    
    Args:
        message: 日志消息
        context: 可选的上下文信息
    """
    logger = _get_system_logger()
    full_message = _format_message_with_context(message, context)
    logger.debug(full_message)


def log_info(message: str, context: Optional[Dict] = None) -> None:
    """
    记录信息级别日志
    
    Args:
        message: 日志消息
        context: 可选的上下文信息
    """
    logger = _get_system_logger()
    full_message = _format_message_with_context(message, context)
    logger.info(full_message)


def log_warning(message: str, context: Optional[Dict] = None) -> None:
    """
    记录警告级别日志
    
    Args:
        message: 日志消息
        context: 可选的上下文信息
    """
    logger = _get_system_logger()
    full_message = _format_message_with_context(message, context)
    logger.warning(full_message)


def log_error(message: str, context: Optional[Dict] = None) -> None:
    """
    记录错误级别日志
    
    Args:
        message: 日志消息
        context: 可选的上下文信息
    """
    logger = _get_system_logger()
    full_message = _format_message_with_context(message, context)
    logger.error(full_message)


def log_critical(message: str, context: Optional[Dict] = None) -> None:
    """
    记录严重错误级别日志
    
    Args:
        message: 日志消息
        context: 可选的上下文信息
    """
    logger = _get_system_logger()
    full_message = _format_message_with_context(message, context)
    logger.critical(full_message)


def log_exception(exception: Exception, additional_info: str = "", context: Optional[Dict] = None) -> str:
    """
    记录异常信息
    
    Args:
        exception: 异常对象
        additional_info: 额外的上下文信息
        context: 可选的上下文信息字典
    
    Returns:
        str: 格式化的错误信息
    """
    logger = _get_system_logger()
    
    # 获取异常的基本信息
    exc_type = type(exception).__name__
    exc_message = str(exception)
    
    # 限制异常消息长度
    if len(exc_message) > 500:
        exc_message = exc_message[:500] + "... [消息过长已截断]"
    
    # 优化堆栈信息记录，避免过长
    traceback_lines = traceback.format_exc().split('\n')
    if len(traceback_lines) > 15:
        traceback_str = '\n'.join(traceback_lines[:5])  # 保留异常类型和前几行
        traceback_str += '\n... [中间堆栈已省略]\n'
        traceback_str += '\n'.join(traceback_lines[-10:])  # 保留最近的调用信息
    else:
        traceback_str = '\n'.join(traceback_lines)
    
    # 构建优化的错误信息
    error_info = f"异常: {exc_type}\n信息: {exc_message}\n"
    
    # 添加额外信息
    if additional_info:
        # 确保additional_info是字符串
        info_str = str(additional_info)
        if len(info_str) > 200:
            info_str = info_str[:200] + "... [信息过长已截断]"
        error_info += f"额外信息: {info_str}\n"
    
    # 添加上下文信息
    if context:
        try:
            context_str = json.dumps(context, ensure_ascii=False, indent=2)
            error_info += f"上下文: {context_str}\n"
        except Exception:
            error_info += f"上下文: [序列化失败] {str(context)}\n"
    
    error_info += f"堆栈: {traceback_str}"
    
    logger.error(error_info)
    return error_info


def _format_message_with_context(message: str, context: Optional[Dict] = None) -> str:
    """
    格式化带上下文的日志消息
    
    Args:
        message: 原始消息
        context: 上下文信息
        
    Returns:
        str: 格式化后的消息
    """
    full_message = message
    if context:
        try:
            context_str = json.dumps(context, ensure_ascii=False, separators=(',', ':'))
            full_message = f"{message} [上下文: {context_str}]"
        except Exception:
            # 如果上下文序列化失败，至少记录原始消息
            full_message = f"{message} [上下文: 序列化失败]"
    return full_message


# =============================================================================
# 操作日志相关功能
# =============================================================================

def _get_operation_logger():
    """
    获取操作日志记录器
    
    Returns:
        OperationLogger: 操作日志记录器实例
    """
    global _operation_logger
    if not _operation_logger:
        try:
            from operation_logger import operation_logger as op_logger
            _operation_logger = op_logger
        except Exception as e:
            log_error(f"初始化操作日志记录器失败: {str(e)}")
            # 创建一个简单的模拟对象，避免应用崩溃
            class MockOperationLogger:
                def log_operation(self, **kwargs):
                    log_debug(f"操作日志[模拟]: {kwargs}")
                def flush_logs(self):
                    pass
            _operation_logger = MockOperationLogger()
    return _operation_logger


def record_operation(
    user_id: Optional[str] = None,
    username: Optional[str] = None,
    operation_module: Optional[str] = None,
    operation_content: Optional[str] = None,
    operation_result: Optional[str] = None,
    detail: Optional[Dict] = None
) -> None:
    """
    记录操作日志
    
    Args:
        user_id: 用户ID
        username: 用户名
        operation_module: 操作模块
        operation_content: 操作内容
        operation_result: 操作结果（成功/失败）
        detail: 详细信息（字典格式）
    """
    try:
        op_logger = _get_operation_logger()
        op_logger.log_operation(
            user_id=user_id,
            username=username or '未知用户',
            operation_module=operation_module or '未知模块',
            operation_content=operation_content or '未知操作',
            operation_result=operation_result or '未知结果',
            detail=detail
        )
    except Exception as e:
        # 确保日志记录本身的错误不会影响应用运行
        log_error(f"记录操作日志失败: {str(e)}")


def record_login(username: str, success: bool = True, detail: Optional[Dict] = None) -> None:
    """
    记录登录操作
    
    Args:
        username: 用户名
        success: 是否成功
        detail: 详细信息
    """
    try:
        op_logger = _get_operation_logger()
        op_logger.log_login(username, success=success, detail=detail)
    except Exception as e:
        log_error(f"记录登录日志失败: {str(e)}")


def record_logout(username: str, detail: Optional[Dict] = None) -> None:
    """
    记录退出登录操作
    
    Args:
        username: 用户名
        detail: 详细信息
    """
    try:
        op_logger = _get_operation_logger()
        op_logger.log_logout(username, detail=detail)
    except Exception as e:
        log_error(f"记录退出登录日志失败: {str(e)}")


def record_contract_operation(
    username: str,
    contract_no: str,
    operation_type: str,
    success: bool = True,
    detail: Optional[Dict] = None
) -> None:
    """
    记录合同操作
    
    Args:
        username: 用户名
        contract_no: 合同编号
        operation_type: 操作类型（创建/编辑/删除等）
        success: 是否成功
        detail: 详细信息
    """
    try:
        op_logger = _get_operation_logger()
        op_logger.log_contract_operation(
            username=username,
            contract_no=contract_no,
            operation_type=operation_type,
            success=success,
            detail=detail
        )
    except Exception as e:
        log_error(f"记录合同操作日志失败: {str(e)}")


def record_rent_record_operation(
    username: str,
    contract_no: str,
    operation_type: str,
    success: bool = True,
    detail: Optional[Dict] = None
) -> None:
    """
    记录租金记录操作
    
    Args:
        username: 用户名
        contract_no: 合同编号
        operation_type: 操作类型（创建/编辑/删除等）
        success: 是否成功
        detail: 详细信息
    """
    try:
        op_logger = _get_operation_logger()
        op_logger.log_rent_record_operation(
            username=username,
            contract_no=contract_no,
            operation_type=operation_type,
            success=success,
            detail=detail
        )
    except Exception as e:
        log_error(f"记录租金记录操作日志失败: {str(e)}")


def record_system_setting_change(
    username: str,
    setting_name: str,
    old_value: Any,
    new_value: Any,
    success: bool = True
) -> None:
    """
    记录系统设置变更
    
    Args:
        username: 用户名
        setting_name: 设置名称
        old_value: 旧值
        new_value: 新值
        success: 是否成功
    """
    try:
        op_logger = _get_operation_logger()
        op_logger.log_system_setting_change(
            username=username,
            setting_name=setting_name,
            old_value=old_value,
            new_value=new_value,
            success=success
        )
    except Exception as e:
        log_error(f"记录系统设置变更日志失败: {str(e)}")


def flush_operation_logs():
    """
    强制刷新所有操作日志到数据库
    """
    try:
        op_logger = _get_operation_logger()
        if hasattr(op_logger, 'flush_logs'):
            op_logger.flush_logs()
    except Exception as e:
        log_error(f"刷新操作日志失败: {str(e)}")


# =============================================================================
# 高级功能：装饰器和上下文管理器
# =============================================================================

def log_exceptions(func: Callable) -> Callable:
    """
    函数异常处理装饰器，捕获并记录函数执行过程中的异常
    
    Args:
        func: 被装饰的函数
        
    Returns:
        Callable: 装饰后的函数
    """
    def wrapper(*args, **kwargs):
        try:
            # 执行原始函数
            return func(*args, **kwargs)
        except Exception as e:
            # 获取调用信息
            func_name = func.__name__
            module_name = func.__module__ or 'unknown'
            
            # 准备上下文信息
            context = {
                'function': f'{module_name}.{func_name}',
                'args_count': len(args),
                'kwargs_keys': list(kwargs.keys())
            }
            
            # 记录异常信息
            log_error(f"函数执行异常: {module_name}.{func_name}")
            log_exception(e, f"调用参数: args={args}, kwargs={kwargs}", context)
            
            # 重新抛出异常以便调用者处理
            raise
    
    # 保留原函数的元数据
    wrapper.__name__ = func.__name__
    wrapper.__doc__ = func.__doc__
    wrapper.__module__ = func.__module__
    
    return wrapper


def log_performance(threshold: float = 1.0) -> Callable:
    """
    函数性能监控装饰器，记录函数执行时间
    
    Args:
        threshold: 记录日志的时间阈值（秒）
        
    Returns:
        Callable: 装饰器函数
    """
    def decorator(func: Callable) -> Callable:
        def wrapper(*args, **kwargs):
            start_time = time.time()
            try:
                result = func(*args, **kwargs)
                return result
            finally:
                end_time = time.time()
                execution_time = end_time - start_time
                
                # 只记录执行时间超过阈值的函数
                if execution_time >= threshold:
                    func_name = func.__name__
                    module_name = func.__module__ or 'unknown'
                    log_info(
                        f"函数性能监控: {module_name}.{func_name}",
                        context={
                            'execution_time': f"{execution_time:.3f}秒",
                            'threshold': f"{threshold}秒"
                        }
                    )
        
        # 保留原函数的元数据
        wrapper.__name__ = func.__name__
        wrapper.__doc__ = func.__doc__
        wrapper.__module__ = func.__module__
        
        return wrapper
    return decorator


class LogContext:
    """
    日志上下文管理器，用于记录代码块的执行情况
    """
    def __init__(self, name: str, log_level: str = 'INFO', log_entry_exit: bool = True):
        """
        初始化日志上下文管理器
        
        Args:
            name: 上下文名称
            log_level: 日志级别
            log_entry_exit: 是否记录进入和退出信息
        """
        self.name = name
        self.log_level = log_level
        self.log_entry_exit = log_entry_exit
        self.start_time = 0
    
    def __enter__(self):
        """
        进入上下文
        """
        self.start_time = time.time()
        if self.log_entry_exit:
            log_func = self._get_log_function()
            log_func(f"进入上下文: {self.name}")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        退出上下文
        """
        execution_time = time.time() - self.start_time
        
        if exc_type:
            # 发生异常
            log_error(
                f"上下文 {self.name} 执行异常",
                context={
                    'execution_time': f"{execution_time:.3f}秒",
                    'exception_type': exc_type.__name__
                }
            )
            log_exception(exc_val, f"上下文执行异常: {self.name}")
        elif self.log_entry_exit:
            # 正常退出
            log_func = self._get_log_function()
            log_func(
                f"退出上下文: {self.name}",
                context={'execution_time': f"{execution_time:.3f}秒"}
            )
        
        # 不抑制异常
        return False
    
    def _get_log_function(self):
        """
        根据日志级别获取对应的日志函数
        """
        if self.log_level == 'DEBUG':
            return log_debug
        elif self.log_level == 'INFO':
            return log_info
        elif self.log_level == 'WARNING':
            return log_warning
        elif self.log_level == 'ERROR':
            return log_error
        elif self.log_level == 'CRITICAL':
            return log_critical
        return log_info


# =============================================================================
# 工具函数：获取系统信息
# =============================================================================

def get_system_info() -> Dict[str, str]:
    """
    获取系统信息，用于日志记录
    
    Returns:
        dict: 系统信息字典
    """
    info = {
        'python_version': sys.version,
        'platform': sys.platform,
        'host_name': socket.gethostname(),
        'timestamp': datetime.now().isoformat()
    }
    
    # 尝试获取IP地址
    try:
        ip_addresses = socket.gethostbyname_ex(socket.gethostname())[2]
        # 过滤掉回环地址
        valid_ips = [ip for ip in ip_addresses if ip != '127.0.0.1']
        info['ip_address'] = valid_ips[0] if valid_ips else '127.0.0.1'
    except Exception:
        info['ip_address'] = '未知IP'
    
    return info


# =============================================================================
# 初始化
# =============================================================================

# 初始化系统日志
_initialize_system_logger()

# 记录模块加载信息
log_info("优化版日志集成模块已加载", context=get_system_info())


# =============================================================================
# 导出接口
# =============================================================================

__all__ = [
    # 日志级别常量
    'LOG_LEVELS',
    
    # 系统日志函数
    'log_debug',
    'log_info',
    'log_warning',
    'log_error',
    'log_critical',
    'log_exception',
    
    # 操作日志函数
    'record_operation',
    'record_login',
    'record_logout',
    'record_contract_operation',
    'record_rent_record_operation',
    'record_system_setting_change',
    'flush_operation_logs',
    
    # 高级功能
    'log_exceptions',
    'log_performance',
    'LogContext',
    
    # 工具函数
    'get_system_info'
]
